use chrono::Local;
use std::path::PathBuf;
use tokio::fs;
use crate::error::{DownloadError, DownloadResult};

/// 生成基于当前时间的文件名
pub fn generate_timestamped_filename() -> String {
    let now = Local::now();
    format!("{}.ts", now.format("%Y%m%d%H%M%S"))
}

/// URL和文件名的结构体
#[derive(Debug, Clone)]
pub struct UrlWithFilename {
    pub url: String,
    pub filename: Option<String>,
}

/// 从文件读取 URL 列表（支持URL后面指定文件名）
pub async fn read_urls_from_file(file_path: &str) -> DownloadResult<Vec<String>> {
    let url_entries = read_urls_with_filenames_from_file(file_path).await?;
    Ok(url_entries.into_iter().map(|entry| entry.url).collect())
}

/// 从文件读取 URL 列表和文件名
pub async fn read_urls_with_filenames_from_file(file_path: &str) -> DownloadResult<Vec<UrlWithFilename>> {
    if !PathBuf::from(file_path).exists() {
        return Err(DownloadError::Io(format!("URL 文件不存在: {file_path}")));
    }
    
    let content = fs::read_to_string(file_path).await?;
    let mut urls = Vec::new();
    
    for line in content.lines() {
        let line = line.trim();
        
        // 过滤条件：
        // 1. 不是空行
        // 2. 不是以 # 开头的注释行
        if line.is_empty() || line.starts_with('#') {
            continue;
        }
        
        // 解析URL和可选的文件名（用空格或tab分隔）
        let parts: Vec<&str> = line.split_whitespace().collect();
        if parts.is_empty() {
            continue;
        }
        
        let url = parts[0];
        // 检查是否是有效的URL
        if !(url.starts_with("http://") || url.starts_with("https://")) {
            continue;
        }
        
        // 不再过滤URL，让下载器自己处理所有URL
        
        let filename = if parts.len() > 1 {
            Some(parts[1].to_string())
        } else {
            None
        };
        
        urls.push(UrlWithFilename {
            url: url.to_string(),
            filename,
        });
    }
    
    if urls.is_empty() {
        return Err(DownloadError::Io(format!("文件 {file_path} 中没有找到有效的 URL")));
    }
    
    Ok(urls)
}

/// 检查是否为双击启动
pub fn is_double_clicked() -> bool {
    std::env::args().len() == 1
}

/// 双击启动时显示控制台 (Windows 专用)
#[cfg(target_os = "windows")]
pub fn show_console() {
    // 在 Windows 上，如果是双击启动，会自动分配控制台
    // 这里可以添加更多的控制台设置
    println!("🔔 检测到双击启动，已自动打开控制台");
}

/// 非 Windows 系统的空实现
#[cfg(not(target_os = "windows"))]
pub fn show_console() {
    // 非 Windows 系统不需要特殊处理
    println!("🔔 检测到双击启动");
}

/// 验证 URL 格式
pub fn validate_url(url: &str) -> DownloadResult<()> {
    if !url.starts_with("http://") && !url.starts_with("https://") {
        return Err(DownloadError::Url("URL 必须以 http:// 或 https:// 开头".to_string()));
    }
    Ok(())
}

/// 确保目录存在
pub async fn ensure_dir_exists(path: &PathBuf) -> DownloadResult<()> {
    if !path.exists() {
        fs::create_dir_all(path).await?;
    }
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::TempDir;
    use tokio::fs;
    use std::env;

    #[test]
    fn test_generate_timestamped_filename() {
        let filename = generate_timestamped_filename();
        
        // 验证文件名格式
        assert!(filename.ends_with(".ts"));
        assert_eq!(filename.len(), 17); // YYYYMMDDHHMMSS.ts = 14 + 3 = 17
        
        // 验证包含数字和点
        let name_part = &filename[..14];
        assert!(name_part.chars().all(|c| c.is_ascii_digit()));
        
        // 测试连续生成的文件名不同（至少在秒级别）
        tokio_test::block_on(async {
            let filename1 = generate_timestamped_filename();
            tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
            let filename2 = generate_timestamped_filename();
            
            // 由于时间戳精确到秒，短时间内可能相同，这是正常的
            // 主要验证格式正确性
            assert!(filename1.ends_with(".ts"));
            assert!(filename2.ends_with(".ts"));
        });
    }

    #[tokio::test]
    async fn test_read_urls_with_filenames_from_file() {
        let temp_dir = TempDir::new().unwrap();
        let file_path = temp_dir.path().join("test_urls_with_filenames.txt");
        
        // 创建测试文件（模拟真实的urls.txt）
        let content = "# yt-dlp-rs URL 列表文件\n\
# 每行一个 m3u8 URL，空行和以 # 开头的行会被忽略\n\
\n\
# 添加您的 m3u8 URL\n\
https://surrit.com/80578501-ee80-4633-9c30-acbae2cf2f76/720p/video.m3u8  01.mp4\n\
https://surrit.com/8dd7b081-0bd9-47d8-98c5-1e0435e55683/720p/video.m3u8  02.mp4\n\
#https://surrit.com/460c582d-83af-4a48-9bc7-8df7b0806b45/720p/video.m3u8\n\
https://example.com/no-filename.m3u8\n";
        fs::write(&file_path, content).await.unwrap();
        
        let entries = read_urls_with_filenames_from_file(file_path.to_str().unwrap()).await.unwrap();
        
        assert_eq!(entries.len(), 3);
        
        // 第一个URL有指定文件名
        assert_eq!(entries[0].url, "https://surrit.com/80578501-ee80-4633-9c30-acbae2cf2f76/720p/video.m3u8");
        assert_eq!(entries[0].filename, Some("01.mp4".to_string()));
        
        // 第二个URL有指定文件名
        assert_eq!(entries[1].url, "https://surrit.com/8dd7b081-0bd9-47d8-98c5-1e0435e55683/720p/video.m3u8");
        assert_eq!(entries[1].filename, Some("02.mp4".to_string()));
        
        // 第三个URL没有指定文件名
        assert_eq!(entries[2].url, "https://example.com/no-filename.m3u8");
        assert_eq!(entries[2].filename, None);
    }

    #[tokio::test]
    async fn test_read_urls_from_file_with_comments() {
        let temp_dir = TempDir::new().unwrap();
        let file_path = temp_dir.path().join("commented_urls.txt");
        
        // 创建包含注释的文件（模拟你的urls.txt）
        let content = "# yt-dlp-rs URL 列表文件\n\
# 每行一个 m3u8 URL，空行和以 # 开头的行会被忽略\n\
\n\
# 示例 URLs (请替换为实际的 m3u8 URL)\n\
\n\
\n\
# 添加您的 m3u8 URL:\n\
https://surrit.com/80578501-ee80-4633-9c30-acbae2cf2f76/720p/video.m3u8\n\
#https://surrit.com/8dd7b081-0bd9-47d8-98c5-1e0435e55683/720p/video.m3u8\n\
#https://surrit.com/460c582d-83af-4a48-9bc7-8df7b0806b45/720p/video.m3u8\n";
        fs::write(&file_path, content).await.unwrap();
        
        let urls = read_urls_from_file(file_path.to_str().unwrap()).await.unwrap();
        
        // 应该只有一个有效URL，注释的两个被忽略
        assert_eq!(urls.len(), 1);
        assert_eq!(urls[0], "https://surrit.com/80578501-ee80-4633-9c30-acbae2cf2f76/720p/video.m3u8");
    }

    #[tokio::test]
    async fn test_read_urls_from_file_not_exist() {
        let result = read_urls_from_file("nonexistent_file.txt").await;
        
        assert!(result.is_err());
        assert!(matches!(result.unwrap_err(), crate::error::DownloadError::Io(_)));
    }

    #[tokio::test]
    async fn test_read_urls_from_file_empty() {
        let temp_dir = TempDir::new().unwrap();
        let file_path = temp_dir.path().join("empty_urls.txt");
        
        // 创建空文件
        fs::write(&file_path, "").await.unwrap();
        
        let result = read_urls_from_file(file_path.to_str().unwrap()).await;
        
        assert!(result.is_err());
        assert!(matches!(result.unwrap_err(), crate::error::DownloadError::Io(_)));
    }

    #[tokio::test]
    async fn test_read_urls_from_file_no_valid_urls() {
        let temp_dir = TempDir::new().unwrap();
        let file_path = temp_dir.path().join("invalid_urls.txt");
        
        // 创建只包含无效URL的文件
        let content = "# 这是注释\n\n无效的URL\nftp://example.com/file\n";
        fs::write(&file_path, content).await.unwrap();
        
        let result = read_urls_from_file(file_path.to_str().unwrap()).await;
        
        assert!(result.is_err());
        assert!(matches!(result.unwrap_err(), crate::error::DownloadError::Io(_)));
    }

    #[tokio::test]
    async fn test_read_urls_from_file_mixed_content() {
        let temp_dir = TempDir::new().unwrap();
        let file_path = temp_dir.path().join("mixed_urls.txt");
        
        // 创建包含各种内容的文件
        let content = "# 注释行\nhttps://example.com/video1.m3u8\n\n   \nhttp://example.com/video2.m3u8  \n无效行\nhttps://example.com/video3.m3u8\nftp://invalid.com/file\n";
        fs::write(&file_path, content).await.unwrap();
        
        let urls = read_urls_from_file(file_path.to_str().unwrap()).await.unwrap();
        
        assert_eq!(urls.len(), 3);
        assert!(urls.iter().all(|url| url.starts_with("http")));
    }

    #[test]
    fn test_is_double_clicked() {
        // 这个测试比较难模拟，因为它依赖于实际的命令行参数
        // 我们只能测试函数不会panic
        let _result = is_double_clicked();
        // 函数正常返回，不需要额外验证
    }

    #[test]
    fn test_show_console() {
        // 测试函数不会panic
        show_console(); // 应该正常执行而不崩溃
    }

    #[test]
    fn test_validate_url_valid() {
        let valid_urls = vec![
            "http://example.com",
            "https://example.com",
            "http://example.com/path",
            "https://example.com/path?query=value",
            "https://subdomain.example.com:8080/path",
        ];
        
        for url in valid_urls {
            let result = validate_url(url);
            assert!(result.is_ok(), "URL应该有效: {url}");
        }
    }

    #[test]
    fn test_validate_url_invalid() {
        let invalid_urls = vec![
            "ftp://example.com",
            "example.com",
            "www.example.com",
            "//example.com",
            "htp://example.com", // 拼写错误
            "",
            "not-a-url",
        ];
        
        for url in invalid_urls {
            let result = validate_url(url);
            assert!(result.is_err(), "URL应该无效: {url}");
            assert!(matches!(result.unwrap_err(), crate::error::DownloadError::Url(_)));
        }
    }

    #[tokio::test]
    async fn test_ensure_dir_exists_new_dir() {
        let temp_dir = TempDir::new().unwrap();
        let new_dir = temp_dir.path().join("new_directory");
        
        assert!(!new_dir.exists());
        
        let result = ensure_dir_exists(&new_dir).await;
        assert!(result.is_ok());
        assert!(new_dir.exists());
        assert!(new_dir.is_dir());
    }

    #[tokio::test]
    async fn test_ensure_dir_exists_existing_dir() {
        let temp_dir = TempDir::new().unwrap();
        let existing_dir = temp_dir.path().to_path_buf();
        
        assert!(existing_dir.exists());
        
        let result = ensure_dir_exists(&existing_dir).await;
        assert!(result.is_ok());
        assert!(existing_dir.exists());
    }

    #[tokio::test]
    async fn test_ensure_dir_exists_nested_dirs() {
        let temp_dir = TempDir::new().unwrap();
        let nested_dir = temp_dir.path().join("level1").join("level2").join("level3");
        
        assert!(!nested_dir.exists());
        
        let result = ensure_dir_exists(&nested_dir).await;
        assert!(result.is_ok());
        assert!(nested_dir.exists());
        assert!(nested_dir.is_dir());
    }

    #[tokio::test]
    async fn test_ensure_dir_exists_permission_error() {
        // 在某些系统上测试权限错误比较困难
        // 这里主要测试函数签名和基本功能
        let temp_dir = TempDir::new().unwrap();
        let test_dir = temp_dir.path().join("test_permissions");
        
        let result = ensure_dir_exists(&test_dir).await;
        assert!(result.is_ok()); // 在临时目录中应该有权限
    }

    #[test]
    fn test_args_simulation() {
        // 测试命令行参数的模拟情况
        let original_args: Vec<String> = env::args().collect();
        
        // 验证我们可以读取参数（不修改，只是测试访问）
        assert!(!original_args.is_empty());
        assert!(original_args[0].contains("yt-dlp") || original_args[0].contains("test"));
    }
}